fix: reconcile API key expiry docs with server-side 365-day cap - #407
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
|
Claude finished @mintlify[bot]'s task in 3m 18s —— View job Doc review — PR #407Advisory review per the Improvements1. Line 61 says omitting it yields the 365-day maximum; line 96 says removing a previously set value leaves the existing expiry unchanged. Both are true, for creation and for an existing resource respectively, but the page no longer distinguishes them — the clause that used to explain the follow-up ( 2.
3. Both Warnings offer 4. Incomplete sweep — the key-creation pages still say nothing about the cap
These are where a reader actually picks an expiry, and neither mentions that TTL is capped or that no-expiry is gone. The PR reconciled the Terraform and rotation surfaces but not the two UI creation surfaces. Confirm first whether Suggestion
The "capture directly into your secrets store" example still sends Related, and also posted inline: the new example dates are all near-term and fixed — Upstream — does not block this merge
One thing the PR body doesn't cover: the 3 Improvements inline, 1 Improvement + 1 Suggestion above, 1 upstream note. Nothing Critical: no new pages, no moves, no relative links, and every internal target in the changed files resolves (checked by hand — |
| - **Omitted** → the server applies the maximum 365-day expiry. | ||
| - **Set within 365 days** → honored as-is. | ||
| - **Set beyond 365 days** → silently shortened to the 365-day cap. Terraform then reports the result as an inconsistent result after apply and marks the resource tainted so the next apply revokes and recreates it. Choose an `expires_at` within the 365-day window to avoid this. | ||
| - **In the past** → rejected server-side at apply time. | ||
|
|
||
| Keys that never expire can no longer be created. |
There was a problem hiding this comment.
The "Omitted → the server applies the maximum 365-day expiry" bullet is true only at creation, and it now reads as contradicting the schema entry at line 96 ("Removing a previously set value from configuration leaves the existing expiry unchanged").
The old text closed that gap with the trailing clause you removed (to get a non-expiring key again, the key must be recreated (e.g. via terraform taint ...)). Without it, a reader who deletes expires_at from a live resource to "reset the clock to 365 days" gets no change at all, and the page doesn't say how to actually get a fresh key.
| - **Omitted** → the server applies the maximum 365-day expiry. | |
| - **Set within 365 days** → honored as-is. | |
| - **Set beyond 365 days** → silently shortened to the 365-day cap. Terraform then reports the result as an inconsistent result after apply and marks the resource tainted so the next apply revokes and recreates it. Choose an `expires_at` within the 365-day window to avoid this. | |
| - **In the past** → rejected server-side at apply time. | |
| Keys that never expire can no longer be created. | |
| - **Omitted at creation** → the server applies the maximum 365-day expiry. | |
| - **Set within 365 days** → honored as-is. | |
| - **Set beyond 365 days** → silently shortened to the 365-day cap. Terraform then reports `Provider produced inconsistent result after apply`, and the key you get does not have the expiry you asked for. Choose an `expires_at` within the 365-day window to avoid this. | |
| - **In the past** → rejected server-side at apply time. | |
| Keys that never expire can no longer be created. Removing `expires_at` from an existing resource does not extend the key — the expiry set at creation stands. To mint a replacement with a fresh 365 days, force a new key with `terraform apply -replace=kosli_service_account_api_key.ci_key`. |
Two things folded into the suggestion, take or leave independently:
marks the resource tainted so the next apply revokes and recreates itis a specific Terraform-mechanics claim I can't verify from this repo.Provider produced inconsistent result after applyis an error diagnostic; whether the object ends up tainted and auto-recreated depends on the operation and Terraform version, andterraform tainthas been deprecated in favour of-replace=since 0.15.2. Either confirm it against a real apply ofinternal/provider/resource_service_account_api_key.goor state only the part that's certain.-replace=as the documented remedy, since the page no longer mentions any way to get a fresh key.
| <Warning> | ||
| Rotation on its own does not extend the credential. If the rotated key is already close to its expiry (for example, most of the way through the 365-day cap), the new key inherits that expiry and dies at the same moment — the exact failure rotation is supposed to prevent. Pass `--expires-at` to reset the clock, up to the 365-day cap. | ||
| </Warning> |
There was a problem hiding this comment.
The Warning's only remedy is --expires-at, but the Web UI tab (lines 38–45) is the first tab and offers only a grace period — no expiry field. So the reader most likely to hit this failure mode is the one given no way to fix it.
administration/authentication/service_accounts.md:24 shows the create dialog does have a TTL field. If Regenerate has one too, document it in step 5 of the Web UI tab and reference it here. If it doesn't, say so explicitly, e.g.:
…Pass
--expires-at(CLI) orexpires_at(API) to reset the clock, up to the 365-day cap. Rotating in the web app always inherits the old key's expiry — use the CLI or API when you need to extend it.
Same applies to the Warning at administration/authentication/api_key_rotation.md:20-22, which names only the CLI flag.
| kosli rotate api-key <<key-id>> \ | ||
| --service-account <<service-account-name>> \ | ||
| --grace-period-hours 24 \ | ||
| --expires-at 2026-12-31 \ |
There was a problem hiding this comment.
2026-12-31 is 111 days out from today, and the docs state past values are rejected server-side. From 2027-01-01 this becomes an example that errors when copied. The old 2100-01-01 violated the cap but never went stale; swapping in a fixed near-term date trades one wrong example for one with an expiry date of its own.
This page already uses the <<...>> placeholder convention for <<key-id>> and <<service-account-name>>, so:
| --expires-at 2026-12-31 \ | |
| --expires-at <<YYYY-MM-DD>> \ |
Same issue at line 89 — 1798761600 is 2027-01-01 — and in terraform-reference/resources/service_account_api_key.mdx at lines 45, 59 and 96 (2026-12-31T00:00:00Z), plus line 68's timeadd("2026-01-01T00:00:00Z", "8760h"), which resolves to 2027-01-01 and so goes stale on the same date despite looking dynamic.
Addresses the two API key expiry issues raised in review.
Server-side confirmation
Verified in
kosli-dev/server:src/lib/constants.py—MAX_API_KEY_LIFETIME_DAYS = 365.src/model/api_key.py::clamp_expires_at— omittingexpires_atyieldsmax_api_key_expires_at(); a later value is clamped to it. Enforced server-side, so every surface (CLI, Terraform, direct API) hits the same rule.src/fastapi_app/models/service_accounts.py— request-model description already states this for both create (ApiKeyPostInput) and rotate (ApiKeyRotateInput, defaulting the new key to the rotated key's current expiry, capped by the maximum).1.
terraform-reference/resources/service_account_api_key.mdx# A non-expiring API keyexample comment.## Expiryto state every key expires, the 365-day cap, and what happens whenexpires_atis omitted / within-cap / beyond-cap / in the past. Called out the Terraform-specific consequence of a longerexpires_at(server clamps → inconsistent result after apply → resource marked tainted → next apply recreates).Optional > expires_atschema description to match.2100-01-01to2026-12-31so they fit inside the 365-day cap.Upstream:
kosli-dev/terraform-provider-kosliinternal/provider/resource_service_account_api_key.go:76already carries the correct schema description ("silently shortens a longer expiry", "keys that never expire can no longer be created"). The next agent sync ofterraform-reference/will overwrite this page with wording aligned to what I've just written, so no upstream change is needed.2. Rotation docs
administration/authentication/api_key_rotation.mdandtutorials/rotating_api_keys.mdx:--expires-at/expires_atis passed, bounded by the 365-day cap.<Warning>on both pages spelling out the failure mode: a key rotated near end-of-life produces a replacement that dies at the same moment — the very failure rotation is supposed to prevent.--expires-atalongside--grace-period-hours, and the API tab example includesexpires_at.Not fixed here (out of scope)
client_reference/kosli_create_api-key.mdandkosli_rotate_api-key.mdstill say "Defaults to no expiry". These are agent-synced fromkosli-dev/cli(cmd/kosli/root.go:157-158— where the flag descriptions already match v2.40.1: "Keys always expire: when not set, the key gets the maximum allowed lifetime..." and "Defaults to the rotated key's current expiry, and is capped by the maximum allowed key lifetime"). Next CLI reference sync will pick this up.Validation
mint validateandmint broken-linksclean on the changed pages.Generated by Mintlify Agent.
Requested by: marko@kosli.com via Slack
Mintlify session: slack_1778705097.340389_D0ALT8RK1CJ